﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Xml;

namespace SHomeWorkshop.LunarMind
{
    public class ModifingItem
    {
        /// <summary>
        /// 这是Operation改动的各对象的集合，——通常只有一个成员。
        /// 注意：如果是插入或删除了一个公式，则“modifiedObjects”值并不是公式所拥有的属性。
        /// “插入公式”使用“InsertExpression”，“删除公式”使用“DeleteExpression”。
        /// </summary>
        private List<Action> modifiedPropertyAndValues = new List<Action>();

        /// <summary>
        /// 根据这个列表找到对公式进行了哪些修改。
        /// </summary>
        internal List<Action> ModifiedPropertyAndValues
        {
            get { return modifiedPropertyAndValues; }
        }

        /// <summary>
        /// 只是封装了modifiedPropertyAndValues.Add()方法。
        /// </summary>
        /// <param name="action"></param>
        public void Add(Action action)
        {
            this.modifiedPropertyAndValues.Add(action);
        }

        /// <summary>
        /// 只是封装了modifiedPropertyAndValues.Insert()方法。
        /// </summary>
        /// <param name="action"></param>
        public void Insert(int index, Action action)
        {
            this.modifiedPropertyAndValues.Insert(index, action);
        }

        /// <summary>
        /// 编辑器卷动位置。
        /// </summary>
        public Point EditorOffset { get; set; }

        /// <summary>
        /// 如果操作可能造成布局改变，则应将此值置为true，以便在撤销、重做后重新布局。
        /// </summary>
        public bool IsNeedRefreshTitleAndLinesLocation { get; set; } = false;

        public bool IsNeedRefreshRelations { get; set; } = false;

        public string NewSelectedTitleID { get; set; } = null;

        public string OldSelectedTitleID { get; set; } = null;

        public string OldSelectedTitleImageID { get; set; } = null;

        public string NewSelectedTitleImageID { get; set; } = null;

        private string modifingName = "..操作..";

        public string ModifingName
        {
            get { return modifingName; }
            set { modifingName = value; }
        }
    }

    /// <summary>
    /// 操作的类型。
    /// </summary>
    public enum ActionType
    {
        Property,                       //修改属性——大部分操作都是这个类型。
        InsertTitle,                    //插入标题
        DeleteTitle,                    //删除标题
        InsertTitleImage,               //插入标题图片
        DeleteTitleImage,               //删除标题图片

        AddRelation,
        DeleteRelation,
        AddComment,
        DeleteComment,
        AddPictureBox,
        DeletePictureBox,
        ViewMode,                       //更改视图模式
        AddFixedTitle,
        SetDocumentPadding,
        SetDocumentBackground,          //更改文档背景
        DefaultFontSize,

        //TODO: 其它操作类型应添加在此处。
    };

    public class Action
    {
        /// <summary>
        /// 构造存放在UndoItem的Properties列表中的各（将被更改的）属性及其值的文本表示。
        /// ——通常这个列表中只有一个属性及其值。
        /// </summary>
        /// <param name="id">公式内部编号(Guid)。</param>
        /// <param name="index">公式索引。</param>
        /// <param name="exClassName">公式类的名称。</param>
        /// <param name="propertyOrActionTypeName">属性名。</param>
        /// <param name="oldValue">旧属性值的文本表示方式。</param>
        /// <param name="newValue">新属性值的文本表示方式。</param>
        /// <param name="actionType">“修改操作”的类型。默认是对某个公式的某个属性进行操作。</param>
        /// <param name="higherOrMasterID">此参数只对“插入”或“删除”Action有效。指定上级标题的内部编号。
        /// ★注意：如果是“插入/删除网格子面板”则应传入网格式的内部编号。</param>
        public Action(string id, int index, string exClassName,
            string propertyOrActionTypeName, string oldValue, string newValue, ActionType actionType = ActionType.Property,
            string higherOrMasterID = "")
        {
            this.id = id;
            this.titleIndex = index;
            this.className = exClassName;
            this.propertyOrActionTypeName = propertyOrActionTypeName;
            this.oldValue = oldValue;
            this.newValue = newValue;
            this.actionType = actionType;
            this.higherLevelID = higherOrMasterID;
        }

        private string propertyOrActionTypeName;

        /// <summary>
        /// 更改或要撤销的属性的名称。
        /// </summary>
        public string PropertyOrActionTypeName
        {
            get { return propertyOrActionTypeName; }
            set { propertyOrActionTypeName = value; }
        }

        private string oldValue;

        /// <summary>
        /// 取旧属性值（以字符串形式表示）。
        /// </summary>
        public string OldValue
        {
            get { return oldValue; }
        }

        private string newValue;

        /// <summary>
        /// 取新属性值（以字符串形式表示）。
        /// </summary>
        public string NewValue
        {
            get { return newValue; }
        }

        private string id = string.Empty;

        /// <summary>
        /// 根据这个属性找到对哪个公式作了修改。
        /// </summary>
        public string ID
        {
            get { return id; }
        }

        private string className;

        /// <summary>
        /// 标题类或关系线类名称。不应该出现抽象类。
        /// </summary>
        public string ClassName
        {
            get { return className; }
            set { className = value; }
        }

        private int titleIndex;

        /// <summary>
        /// 被修改的标题在其上级的所有下级标题中（也就是兄弟标题中）的位置索引。
        /// </summary>
        public int TitleIndex
        {
            get { return titleIndex; }
            set { titleIndex = value; }
        }

        private ActionType actionType = ActionType.Property;

        public ActionType ActionType
        {
            get { return actionType; }
            set { actionType = value; }
        }

        private string higherLevelID = string.Empty;

        /// <summary>
        /// 插入标题时上级标题的内部编号。
        /// </summary>
        public string HigherLevelID
        {
            get { return higherLevelID; }
        }
    }

    public class ModifingsList : List<ModifingItem>
    {
        /// <summary>
        /// 构造一个“可撤销项”的列表。
        /// </summary>
        /// <param name="editor">所属编辑器。</param>
        public ModifingsList(MainWindow parentEditor)
        {
            this.editor = parentEditor;
        }

        private MainWindow editor;

        public MainWindow Editor
        {
            get { return editor; }
        }

        //对于editor来说，如果下一步进行的操作不是Redo，则应删除多余“可撤销项目”。
        private int point = -1;

        /// <summary>
        /// 表示当前Undo到哪一步，这是个List的索引。
        /// </summary>
        public int Point
        {
            get { return point; }
        }

        private int pointOfSaving = -1;

        /// <summary>
        /// 表示执行“保存”操作时的Point。如果撤销或重做后，与此值相等，则表示
        /// 当前应显示为“已保存”。
        /// </summary>
        public int PointOfSaving
        {
            get { return pointOfSaving; }
            set { pointOfSaving = value; }
        }

        /// <summary>
        /// 执行某一项修改时，将修改信息添加到列表中。
        /// 并删除列表中在当前Point之后的所有项——这些项将不能再用于Redo。
        /// </summary>
        public void Do(ModifingItem modifingItem)
        {
            if (modifingItem != null && this.Contains(modifingItem))
            {
                MessageBox.Show("出现异常，撤销项被重复添加！",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (this.point > -1)
            {
                for (int i = this.Count - 1; i > point; i--)
                {
                    this.RemoveAt(i);
                }
            }
            else
            {
                this.Clear();
            }

            if (PointOfSaving > point)
            {
                PointOfSaving = -2;
            }

            if (modifingItem != null)
            {
                this.Add(modifingItem);
                this.point++;
            }

            RefreshUndoAndRedoButtonTooltip();
        }

        /// <summary>
        /// 能否重做。
        /// </summary>
        public bool CanRedo
        {
            get
            {
                if (Point < -1 || Point > this.Count - 2)//减2，是因为Redo运算时会先加1。最大索引值只能是Count-1。
                {
                    return false;
                }

                if (this.Count <= 0) return false;
                return true;
            }
        }

        /// <summary>
        /// 将Point后移一位，并将目标公式的状态（相关属性值）刷新为新位置（Point）记录的NewValue。
        /// </summary>
        public void Redo()
        {
            if (CanRedo == false) return;

            //注意：此处与Undo不同，得先加。
            point++;

            ModifingItem mi = this[point] as ModifingItem;

            int deletedTitleCount = 0;

            foreach (Action action in mi.ModifiedPropertyAndValues)
            {
                switch (action.ActionType)
                {
                    case ActionType.ViewMode:
                        {
                            Globals.MainWindow.View = (ViewMode)Enum.Parse(typeof(ViewMode), action.NewValue);
                            break;
                        }
                    case ActionType.DefaultFontSize:
                        {
                            Globals.MainWindow.DefaultFontSize = int.Parse(action.NewValue);
                            break;
                        }
                    case ActionType.SetDocumentBackground:
                        {
                            Globals.MainWindow.DocumentBackgroundBrushText = action.NewValue;
                            break;
                        }
                    case ActionType.Property:
                        {
                            if (action.ClassName == typeof(Relation).Name)
                            {
                                Relation relation = editor.GetRelationByID(action.ID);
                                if (relation != null)
                                {
                                    relation.Redo(action);
                                    if (relation == Globals.MainWindow.SelectedRelation)
                                    {
                                        Globals.MainWindow.SelectedRelation = relation;//刷新一下选取状态。
                                    }
                                }
                                else
                                {
                                    deletedTitleCount++;
                                }
                            }
                            else if (action.ClassName == typeof(Comment).Name)
                            {
                                Comment comment = editor.GetCommentByID(action.ID);
                                if (comment != null)
                                {
                                    comment.Redo(action);
                                    if (comment == Globals.MainWindow.SelectedComment)
                                    {
                                        Globals.MainWindow.SelectedComment = comment;//刷新一下选取状态。
                                    }
                                }
                                else
                                {
                                    deletedTitleCount++;
                                }
                            }
                            else if (action.ClassName == typeof(PictureBox).Name)
                            {
                                PictureBox pb = editor.GetPictureBoxByID(action.ID);
                                if (pb != null)
                                {
                                    pb.Redo(action);
                                    if (pb == Globals.MainWindow.SelectedPictureBox)
                                    {
                                        Globals.MainWindow.SelectedPictureBox = pb;//刷新一下选取状态。
                                    }
                                }
                                else
                                {
                                    deletedTitleCount++;
                                }
                            }
                            else if (action.ClassName == typeof(TitleImage).Name)
                            {
                                TitleImage ti = editor.GetTitleImageByID(action.ID);

                                if (ti != null)
                                {
                                    ti.Redo(action);
                                }
                            }
                            else
                            {
                                if (action.PropertyOrActionTypeName == "ImageBase64")
                                {
                                    //这个比较特殊，和图片有关。
                                    Title masterTitle = editor.GetTitleByID(action.HigherLevelID);
                                    if (masterTitle != null)
                                    {
                                        //在更改图片的图像数据时，记录在Action中的ID是图片的ID而不是所在标题的ID；
                                        //而且，此时记录的所谓“上级标题ID”也是所在标题的ID。
                                        TitleImage tImg = masterTitle.GetTitleImageByID(action.ID);
                                        if (tImg != null) tImg.Redo(action);
                                    }
                                    else
                                    {
                                        deletedTitleCount++;
                                    }

                                }
                                else
                                {
                                    Title title = editor.GetTitleByID(action.ID);
                                    if (title != null)
                                    {
                                        title.Redo(action);
                                    }
                                    else
                                    {
                                        deletedTitleCount++;
                                    }
                                }
                            }

                            break;
                        }
                    case ActionType.InsertTitle:
                        {
                            XmlNode titleSetNode = editor.MainXmlDocument.DocumentElement.SelectSingleNode("TitleSet");
                            if (titleSetNode != null)
                            {
                                XmlNode newNode = titleSetNode.AppendXml(action.NewValue);
                                Title newTitle = new Title(editor);
                                newTitle.XmlData = newNode;
                                editor.mainCanvas.Children.Add(newTitle);
                            }

                            break;
                        }
                    case ActionType.InsertTitleImage:
                        {
                            //HigherLevelID中记载的实际上是图像所在的标题的ID.
                            Title masterTitle = editor.GetTitleByID(action.HigherLevelID);
                            if (masterTitle != null)
                            {
                                //action.TitleID实际上是TitleImage自身的ID。
                                TitleImage restoredImage = new TitleImage(masterTitle.Editor, masterTitle);

                                XmlNode imgSetNode = masterTitle.XmlData.SelectSingleNode("ImageSet");
                                if (imgSetNode == null)
                                {
                                    imgSetNode = masterTitle.XmlData.AppendXml("<ImageSet />");
                                }

                                XmlNode restoredNode = imgSetNode.InsertXmlAt(action.NewValue, action.TitleIndex);
                                restoredImage.XmlData = restoredNode;

                                masterTitle.ImgStackPanel.Children.Insert(action.TitleIndex, restoredImage);
                            }
                            break;
                        }
                    case ActionType.AddComment:
                        {
                            XmlNode commentSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("CommentSet");
                            if (commentSet != null)
                            {
                                Title masterTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                Comment willRestoreComment = new Comment(Globals.MainWindow, masterTitle);

                                XmlNode newNode = commentSet.AppendXml(action.NewValue);

                                willRestoreComment.XmlData = newNode;

                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreComment);
                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreComment.ConnectLine);

                                Globals.MainWindow.SelectedComment = willRestoreComment;

                                willRestoreComment.RefreshConnectLine();
                            }

                            break;
                        }
                    case ActionType.AddPictureBox:
                        {
                            XmlNode pbSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("PictureBoxSet");
                            if (pbSet != null)
                            {
                                Title masterTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                PictureBox willRestorePb = new PictureBox(Globals.MainWindow, masterTitle);

                                XmlNode newNode = pbSet.AppendXml(action.NewValue);

                                willRestorePb.XmlData = newNode;

                                Globals.MainWindow.mainCanvas.Children.Add(willRestorePb);
                                Globals.MainWindow.mainCanvas.Children.Add(willRestorePb.ConnectLine);

                                Globals.MainWindow.SelectedPictureBox = willRestorePb;

                                willRestorePb.RefreshConnectLine();
                            }

                            break;
                        }
                    case ActionType.AddFixedTitle:
                        {
                            XmlNode titleSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("TitleSet");
                            if (titleSet != null)
                            {
                                Title masterTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                FixedTitle willRestoreFixedTitle = new FixedTitle(Globals.MainWindow, masterTitle);

                                XmlNode newNode = titleSet.AppendXml(action.NewValue);

                                willRestoreFixedTitle.XmlData = newNode;

                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreFixedTitle);

                                willRestoreFixedTitle.RefreshLoaction();
                                willRestoreFixedTitle.SelectOnlySelf();
                            }

                            break;
                        }
                    case ActionType.AddRelation:
                        {
                            XmlNode relationSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("RelationSet");
                            if (relationSet != null)
                            {
                                Title startTitle = Globals.MainWindow.GetTitleByID(action.OldValue);
                                Title endTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                if (startTitle.ActualHeight == 0 || endTitle.ActualHeight == 0 ||
                                    startTitle.ActualWidth == 0 || endTitle.ActualWidth == 0)
                                {
                                    Globals.MainWindow.RefreshTitleAndLinesLocation();
                                }

                                Relation willRestoreRelation = new Relation(Globals.MainWindow,
                                startTitle,//添加时，action.OldValue中传入的是StartTitleID
                                endTitle//添加时，action.HigherLevelID中传入的是EndTitleID
                                );

                                XmlNode newNode = relationSet.AppendXml(action.NewValue);

                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreRelation);

                                willRestoreRelation.XmlData = newNode;

                                Globals.MainWindow.SelectedRelation = willRestoreRelation;
                            }

                            break;
                        }
                    case ActionType.DeleteTitle:
                        {
                            Title insertedTitle = editor.GetTitleByID(action.ID);
                            if (insertedTitle != null)
                            {
                                XmlNode titleSet = editor.MainXmlDocument.DocumentElement.SelectSingleNode("TitleSet");
                                titleSet.RemoveChild(insertedTitle.XmlData);
                                editor.mainCanvas.Children.Remove(insertedTitle);
                            }
                            break;
                        }
                    case ActionType.DeleteTitleImage:
                        {
                            //HigherLevelID中记载的实际上是图像所在的标题的ID.
                            Title masterTitle = editor.GetTitleByID(action.HigherLevelID);
                            if (masterTitle != null)
                            {
                                //action.TitleID实际上是TitleImage自身的ID。
                                TitleImage insertedImage = masterTitle.GetTitleImageByID(action.ID);

                                XmlNode imgSetNode = masterTitle.XmlData.SelectSingleNode("ImageSet");
                                if (imgSetNode != null)
                                {
                                    imgSetNode.RemoveChild(insertedImage.XmlData);
                                }

                                masterTitle.ImgStackPanel.Children.Remove(insertedImage);
                            }
                            break;
                        }
                    case ActionType.DeleteRelation:
                        {
                            Relation deletedRelation = Globals.MainWindow.GetRelationByID(action.ID);

                            if (deletedRelation != null)
                            {
                                XmlNode relationSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("RelationSet");
                                if (relationSetNode != null)
                                {
                                    relationSetNode.RemoveChild(deletedRelation.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(deletedRelation);

                                Globals.MainWindow.SelectedRelation = null;
                            }

                            break;
                        }
                    case ActionType.DeleteComment:
                        {
                            Comment deleteComment = Globals.MainWindow.GetCommentByID(action.ID);

                            if (deleteComment != null)
                            {
                                XmlNode commentSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("CommentSet");
                                if (commentSetNode != null)
                                {
                                    commentSetNode.RemoveChild(deleteComment.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(deleteComment);
                                Globals.MainWindow.mainCanvas.Children.Remove(deleteComment.ConnectLine);

                                Globals.MainWindow.SelectedComment = null;
                            }

                            break;
                        }
                    case ActionType.DeletePictureBox:
                        {
                            PictureBox deletePb = Globals.MainWindow.GetPictureBoxByID(action.ID);

                            if (deletePb != null)
                            {
                                XmlNode pbSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("PictureBoxSet");
                                if (pbSetNode != null)
                                {
                                    pbSetNode.RemoveChild(deletePb.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(deletePb);
                                Globals.MainWindow.mainCanvas.Children.Remove(deletePb.ConnectLine);

                                Globals.MainWindow.SelectedPictureBox = null;
                            }

                            break;
                        }
                    case ActionType.SetDocumentPadding:
                        {
                            Globals.MainWindow.DocumentPadding = (Thickness)Globals.ThicknessConverter.ConvertFrom(action.NewValue);
                            break;
                        }
                }
            }

            //point++;不能放在此处，而是方法头部。

            RefreshUndoAndRedoButtonTooltip();

            if (mi.IsNeedRefreshTitleAndLinesLocation)
            {
                Globals.MainWindow.RefreshTitleAndLinesLocation();
            }
            else
            {
                //RefreshTitleAndLinesLocation()方法中包括了RefreshRelations()方法的调用，不必重复。
                if (mi.IsNeedRefreshRelations)
                {
                    Globals.MainWindow.RefreshRelations();
                }
            }

            if (mi.NewSelectedTitleID != null && mi.NewSelectedTitleID.Length > 0)
            {
                Title newSelectedTitle = Globals.MainWindow.GetTitleByID(mi.NewSelectedTitleID);
                if (newSelectedTitle != null)
                {
                    newSelectedTitle.SelectOnlySelf();
                }
            }

            if (point == pointOfSaving)
            {
                Editor.IsModified = false;
            }
            else
            {
                Editor.IsModified = true;
            }

            if (Globals.MainWindow.MainSelectedTitle == null)
            {
                Globals.MainWindow.titleDraggingHandler.Visibility = Visibility.Hidden;
            }

            if (mi.NewSelectedTitleImageID != null)
            {
                var newSelTitleImage = Globals.MainWindow.GetTitleImageByID(mi.NewSelectedTitleImageID);
                if (newSelTitleImage != null)
                {
                    Globals.MainWindow.SelectedTitleImage = newSelTitleImage;
                    newSelTitleImage.IsSelected = true;
                }
            }
            else
            {
                if (mi.NewSelectedTitleID != null)
                {
                    var newSelTitle = Globals.MainWindow.GetTitleByID(mi.NewSelectedTitleID);
                    newSelTitle?.SelectOnlySelf();
                }
            }
        }

        public void RefreshUndoAndRedoButtonTooltip()
        {
            if (point >= 0)
            {
                Editor.btnUndo.ToolTip = "撤销：" + this[point].ModifingName;
            }
            else
            {
                Editor.btnUndo.ToolTip = "撤销[Ctrl+Z]";
            }

            if (point < this.Count - 1)
            {
                Editor.btnRedo.ToolTip = "重做：" + this[point + 1].ModifingName;
            }
            else
            {
                Editor.btnRedo.ToolTip = "重做[Ctrl+Y]";
            }
        }

        public bool CanUndo
        {
            get
            {
                if (Point < 0 || Point > this.Count - 1) return false;
                if (this.Count <= 0) return false;
                return true;
            }
        }

        public void Undo()
        {
            if (CanUndo == false) return;

            ModifingItem mi = this[point] as ModifingItem;

            int deletedTitleCount = 0;

            //撤销应逆序！！！
            for (int i = mi.ModifiedPropertyAndValues.Count - 1; i >= 0; i--)
            {
                Action action = mi.ModifiedPropertyAndValues[i];
                switch (action.ActionType)
                {
                    case ActionType.ViewMode:
                        {
                            Globals.MainWindow.View = (ViewMode)Enum.Parse(typeof(ViewMode), action.OldValue);
                            break;
                        }
                    case ActionType.DefaultFontSize:
                        {
                            Globals.MainWindow.DefaultFontSize = int.Parse(action.OldValue);
                            break;
                        }
                    case ActionType.SetDocumentBackground:
                        {
                            Globals.MainWindow.DocumentBackgroundBrushText = action.OldValue;
                            break;
                        }
                    case ActionType.Property:
                        {
                            if (action.ClassName == typeof(Relation).Name)
                            {
                                Relation relation = editor.GetRelationByID(action.ID);
                                if (relation != null)
                                {
                                    relation.Undo(action);

                                    if (relation == Globals.MainWindow.SelectedRelation)
                                    {
                                        Globals.MainWindow.SelectedRelation = relation;//刷新一下选取状态。
                                    }
                                }
                                else
                                {
                                    deletedTitleCount++;
                                }
                            }
                            else if (action.ClassName == typeof(Comment).Name)
                            {
                                Comment comment = editor.GetCommentByID(action.ID);
                                if (comment != null)
                                {
                                    comment.Undo(action);

                                    if (comment == Globals.MainWindow.SelectedComment)
                                    {
                                        Globals.MainWindow.SelectedComment = comment;//刷新选取状态。
                                    }
                                }
                                else
                                {
                                    deletedTitleCount++;
                                }
                            }
                            else if (action.ClassName == typeof(PictureBox).Name)
                            {
                                PictureBox pb = editor.GetPictureBoxByID(action.ID);
                                if (pb != null)
                                {
                                    pb.Undo(action);

                                    if (pb == Globals.MainWindow.SelectedPictureBox)
                                    {
                                        Globals.MainWindow.SelectedPictureBox = pb;//刷新一下选取状态。
                                    }
                                }
                                else
                                {
                                    deletedTitleCount++;//这个其实已经没有意义了。
                                }
                            }
                            else if (action.ClassName == typeof(TitleImage).Name)
                            {
                                TitleImage ti = editor.GetTitleImageByID(action.ID);

                                if (ti != null)
                                {
                                    ti.Undo(action);
                                }
                            }
                            else
                            {
                                if (action.PropertyOrActionTypeName == "ImageBase64")
                                {
                                    //这个比较特殊，和图片有关。
                                    Title masterTitle = editor.GetTitleByID(action.HigherLevelID);
                                    if (masterTitle != null)
                                    {
                                        //在更改图片的图像数据时，记录在Action中的ID是图片的ID而不是所在标题的ID；
                                        //而且，此时记录的所谓“上级标题ID”也是所在标题的ID。
                                        TitleImage tImg = masterTitle.GetTitleImageByID(action.ID);
                                        if (tImg != null) tImg.Undo(action);
                                    }
                                    else
                                    {
                                        deletedTitleCount++;
                                    }

                                }
                                else
                                {
                                    Title title = editor.GetTitleByID(action.ID);
                                    if (title != null)
                                    {
                                        title.Undo(action);
                                    }
                                    else
                                    {
                                        deletedTitleCount++;
                                    }
                                }
                            }

                            break;
                        }
                    case ActionType.InsertTitle:
                        {
                            Title insertedTitle = editor.GetTitleByID(action.ID);
                            if (insertedTitle != null)
                            {
                                XmlNode titleSet = editor.MainXmlDocument.DocumentElement.SelectSingleNode("TitleSet");
                                titleSet.RemoveChild(insertedTitle.XmlData);
                                editor.mainCanvas.Children.Remove(insertedTitle);
                            }
                            break;
                        }
                    case ActionType.InsertTitleImage:
                        {
                            //HigherLevelID中记载的实际上是图像所在的标题的ID.
                            Title masterTitle = editor.GetTitleByID(action.HigherLevelID);
                            if (masterTitle != null)
                            {
                                //action.TitleID实际上是TitleImage自身的ID。
                                TitleImage insertedImage = masterTitle.GetTitleImageByID(action.ID);

                                XmlNode imgSetNode = masterTitle.XmlData.SelectSingleNode("ImageSet");
                                if (imgSetNode != null)
                                {
                                    imgSetNode.RemoveChild(insertedImage.XmlData);
                                }

                                masterTitle.ImgStackPanel.Children.Remove(insertedImage);
                            }
                            break;
                        }
                    case ActionType.AddComment:
                        {
                            Comment addedComment = Globals.MainWindow.GetCommentByID(action.ID);

                            if (addedComment != null)
                            {
                                XmlNode commentSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("CommentSet");
                                if (commentSetNode != null)
                                {
                                    commentSetNode.RemoveChild(addedComment.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(addedComment);
                                Globals.MainWindow.mainCanvas.Children.Remove(addedComment.ConnectLine);

                                Globals.MainWindow.SelectedComment = null;
                            }

                            break;
                        }
                    case ActionType.AddPictureBox:
                        {
                            PictureBox addedPb = Globals.MainWindow.GetPictureBoxByID(action.ID);

                            if (addedPb != null)
                            {
                                XmlNode pbSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("PictureBoxSet");
                                if (pbSetNode != null)
                                {
                                    pbSetNode.RemoveChild(addedPb.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(addedPb);
                                Globals.MainWindow.mainCanvas.Children.Remove(addedPb.ConnectLine);

                                Globals.MainWindow.SelectedPictureBox = null;
                            }
                            break;
                        }
                    case ActionType.AddFixedTitle:
                        {
                            FixedTitle addedFixedTitle = Globals.MainWindow.GetFixedTitleByID(action.ID);

                            if (addedFixedTitle != null)
                            {
                                XmlNode titleSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("TitleSet");
                                if (titleSetNode != null)
                                {
                                    titleSetNode.RemoveChild(addedFixedTitle.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(addedFixedTitle);

                                Globals.MainWindow.ClearAllFromSelectedTitleList();
                            }

                            break;
                        }
                    case ActionType.AddRelation:
                        {
                            Relation addedRelation = Globals.MainWindow.GetRelationByID(action.ID);

                            if (addedRelation != null)
                            {
                                XmlNode relationSetNode = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("RelationSet");
                                if (relationSetNode != null)
                                {
                                    relationSetNode.RemoveChild(addedRelation.XmlData);
                                }

                                Globals.MainWindow.mainCanvas.Children.Remove(addedRelation);

                                Globals.MainWindow.SelectedRelation = null;
                            }

                            break;
                        }
                    case ActionType.DeleteTitle:
                        {
                            XmlNode titleSetNode = editor.MainXmlDocument.DocumentElement.SelectSingleNode("TitleSet");
                            if (titleSetNode != null)
                            {
                                XmlNode newNode = titleSetNode.AppendXml(action.OldValue);

                                Title newTitle;

                                XmlAttribute attrIsFixed = newNode.GetAttribute("IsFixed");
                                if (attrIsFixed != null && attrIsFixed.Value.ToLower() == "true")
                                {
                                    newTitle = new FixedTitle(editor);
                                    newTitle.XmlData = newNode;
                                    editor.mainCanvas.Children.Add(newTitle);
                                    (newTitle as FixedTitle).RefreshLoaction();
                                }
                                else
                                {
                                    newTitle = new Title(editor);
                                    newTitle.XmlData = newNode;
                                    editor.mainCanvas.Children.Add(newTitle);
                                }
                            }
                            break;
                        }
                    case ActionType.DeleteTitleImage:
                        {
                            //HigherLevelID中记载的实际上是图像所在的标题的ID.
                            Title masterTitle = editor.GetTitleByID(action.HigherLevelID);
                            if (masterTitle != null)
                            {
                                //action.TitleID实际上是TitleImage自身的ID。
                                TitleImage restoredImage = new TitleImage(masterTitle.Editor, masterTitle);

                                XmlNode imgSetNode = masterTitle.XmlData.SelectSingleNode("ImageSet");
                                if (imgSetNode == null)
                                {
                                    imgSetNode = masterTitle.XmlData.AppendXml("<ImageSet />");
                                }

                                XmlNode restoredNode = imgSetNode.InsertXmlAt(action.OldValue, action.TitleIndex);
                                restoredImage.XmlData = restoredNode;

                                masterTitle.ImgStackPanel.Children.Insert(action.TitleIndex, restoredImage);
                            }
                            break;
                        }
                    case ActionType.DeleteRelation:
                        {
                            XmlNode relationSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("RelationSet");
                            if (relationSet != null)
                            {
                                Title startTitle = Globals.MainWindow.GetTitleByID(action.NewValue);
                                Title endTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                if (startTitle.ActualHeight == 0 || endTitle.ActualHeight == 0 ||
                                    startTitle.ActualWidth == 0 || endTitle.ActualWidth == 0)
                                {
                                    Globals.MainWindow.RefreshTitleAndLinesLocation();
                                }

                                Relation willRestoreRelation = new Relation(Globals.MainWindow,
                                startTitle,//删除时，action.NewValue中传入的是StartTitleID
                                endTitle//删除时，action.HigherLevelID中传入的是EndTitleID
                                );

                                XmlNode newNode = relationSet.AppendXml(action.OldValue);

                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreRelation);

                                willRestoreRelation.XmlData = newNode;

                                Globals.MainWindow.SelectedRelation = willRestoreRelation;
                            }
                            break;
                        }
                    case ActionType.DeleteComment:
                        {
                            XmlNode commentSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("CommentSet");
                            if (commentSet != null)
                            {
                                Title masterTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                Comment willRestoreComment = new Comment(Globals.MainWindow, masterTitle);

                                XmlNode newNode = commentSet.AppendXml(action.OldValue);

                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreComment);
                                Globals.MainWindow.mainCanvas.Children.Add(willRestoreComment.ConnectLine);

                                willRestoreComment.XmlData = newNode;

                                Globals.MainWindow.SelectedComment = willRestoreComment;
                            }
                            break;
                        }
                    case ActionType.DeletePictureBox:
                        {
                            XmlNode pbSet = Globals.MainWindow.MainXmlDocument.DocumentElement.SelectSingleNode("PictureBoxSet");
                            if (pbSet != null)
                            {
                                Title masterTitle = Globals.MainWindow.GetTitleByID(action.HigherLevelID);

                                PictureBox willRestorePictureBox = new PictureBox(Globals.MainWindow, masterTitle);

                                XmlNode newNode = pbSet.AppendXml(action.OldValue);

                                Globals.MainWindow.mainCanvas.Children.Add(willRestorePictureBox);
                                Globals.MainWindow.mainCanvas.Children.Add(willRestorePictureBox.ConnectLine);

                                willRestorePictureBox.XmlData = newNode;

                                Globals.MainWindow.SelectedPictureBox = willRestorePictureBox;
                            }
                            break;
                        }
                    case ActionType.SetDocumentPadding:
                        {
                            Globals.MainWindow.DocumentPadding =
                                (Thickness)Globals.ThicknessConverter.ConvertFrom(action.OldValue);
                            break;
                        }
                }
            }

            //如果涉及到的所有公式都已经找不到了（被删除了）。则自动跳往下一次Undo。
            //if (deletedExpression >= mi.ModifiedPropertyAndValues.Count)
            //{
            point--;
            //    Undo();
            //}
            //else
            //{
            //    //Undo结束后才有必要令point减少1.——此时才有必要准备Undo前一次更改的值。
            //    point--;
            //}

            RefreshUndoAndRedoButtonTooltip();

            if (mi.IsNeedRefreshTitleAndLinesLocation)
            {
                Globals.MainWindow.RefreshTitleAndLinesLocation();
            }
            else
            {
                //RefreshTitleAndLinesLocation()方法中包括了RefreshRelations()方法的调用，不必重复。
                if (mi.IsNeedRefreshRelations)
                {
                    Globals.MainWindow.RefreshRelations();
                }
            }

            if (mi.OldSelectedTitleID != null && mi.OldSelectedTitleID.Length > 0)
            {
                Title oldSelectedTitle = Globals.MainWindow.GetTitleByID(mi.OldSelectedTitleID);
                if (oldSelectedTitle != null)
                {
                    oldSelectedTitle.SelectOnlySelf();
                }
            }

            if (point == pointOfSaving)
            {
                Editor.IsModified = false;
            }
            else
            {
                Editor.IsModified = true;
            }

            if (Globals.MainWindow.MainSelectedTitle == null)
            {
                Globals.MainWindow.titleDraggingHandler.Visibility = Visibility.Hidden;
            }

            if (mi.OldSelectedTitleImageID != null)
            {
                var oldSelTitleImage = Globals.MainWindow.GetTitleImageByID(mi.OldSelectedTitleImageID);
                if (oldSelTitleImage != null)
                {
                    Globals.MainWindow.SelectedTitleImage = oldSelTitleImage;
                    oldSelTitleImage.IsSelected = true;
                }
            }
            else
            {
                if (mi.OldSelectedTitleID != null)
                {
                    var oldSelTitle = Globals.MainWindow.GetTitleByID(mi.OldSelectedTitleID);
                    oldSelTitle?.SelectOnlySelf();
                }
            }
        }
    }
}
